package network;

import globals.Global;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;

import javax.swing.JOptionPane;

import screen.ScreenType;

public class NetworkManager {
	
	// Send State
	private static final int NETWORK_STATE_CONNECTED = 0;
	private static final int NETWORK_STATE_DISCONNECT = 1;
	
	// Receive State
	private static final int NETWORK_STATE_KICK = 1;
	private static final int NETWORK_STATE_SERVERDISCONNECT = 2;
	
	public static Socket socket;
	
	
	public static String ip = "";
	
	public int state = 0;
	public boolean connected = false;
	
	public int x = 0;
	public int y = 0;
	
	public NetworkManager() {
		
	}
	
	public boolean connect(String serverAddr) {
		try
		{
			ip = serverAddr;
			
			int port = Integer.parseInt(ip.substring(ip.indexOf(":") + 1));
			ip = ip.substring(0, ip.indexOf(":"));
			
			socket = new Socket(ip, port);
			socket.setTcpNoDelay(true);
			
			ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
			oos.writeObject(Global.Instance().username);
			
			ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
			String response = (String) ois.readObject();
			
			if (response.equals("Your name is already taken!"))
			{
				JOptionPane.showMessageDialog(null, response, "Message", JOptionPane.INFORMATION_MESSAGE);
				return false;
			}
			
			connected = true;
			state = NETWORK_STATE_CONNECTED;
			new Thread(send).start();
			new Thread(receive).start();
			
			return true;
		}
		catch (Exception ex)
		{
			JOptionPane.showMessageDialog(null, "Error: " + ex.getMessage(), "Alert", JOptionPane.ERROR_MESSAGE);
			return false;
		}
	}
	
	public void disconnect() {
		state = NETWORK_STATE_DISCONNECT;
		Global.Instance().currentScreen = ScreenType.Menu;
	}
	
	Runnable send = new Runnable()
	{
		@Override
		public void run()
		{
			ObjectOutputStream oos;
			
			while (connected)
			{
				if (socket != null)
				{
					try	{
						DataPackage dp = new DataPackage();
						dp.x = Global.Instance().player.location.x;
						dp.y = Global.Instance().player.location.y;
						dp.xSpeed = Global.Instance().player.xSpeed;
						dp.ySpeed = Global.Instance().player.ySpeed;
						dp.username = Global.Instance().username;
						
						oos = new ObjectOutputStream(socket.getOutputStream());
						oos.writeObject(state);
						
						oos = new ObjectOutputStream(socket.getOutputStream());
						oos.writeObject(dp);
						
						if (state == NETWORK_STATE_DISCONNECT) // Client Disconnected
						{
							connected = false;
							socket.close();
							//socket = null;
						}
					}
					catch (Exception ex) {}
					
					try {
						Thread.sleep(50);
					} catch (Exception e) {}
				}
				else
				{
					break;
				}
			}
		}
	};
	
	Runnable receive = new Runnable()
	{
		@Override
		public void run()
		{
			ObjectInputStream ois;
			
			while (connected)
			{
				try
				{
					ois = new ObjectInputStream(socket.getInputStream());
					int receive_state = (Integer) ois.readObject();
					
					if (receive_state == NETWORK_STATE_KICK) // Kicked / Disconnected by Server
					{
						connected = false;
						socket = null;
						
						JOptionPane.showMessageDialog(null, "Disconnected by Server", "Info", JOptionPane.INFORMATION_MESSAGE);
						disconnect();
					}
					else if (receive_state == NETWORK_STATE_SERVERDISCONNECT) // Server Disconnected
					{
						connected = false;
						socket = null;
						
						JOptionPane.showMessageDialog(null, "Server Disconnected", "Info", JOptionPane.INFORMATION_MESSAGE);
						disconnect();
					}
					
					ois = new ObjectInputStream(socket.getInputStream());
					ArrayList<DataPackage> list_data = (ArrayList<DataPackage>) ois.readObject();
					
					for (int i = 0; i < list_data.size(); i++)
					{
						DataPackage dp = list_data.get(i);
						
						if (list_data.size() != Global.Instance().others.size())
						{
							if (list_data.size() > Global.Instance().others.size())
							{
								Global.Instance().others.add(dp);
							}
							
							if (list_data.size() < Global.Instance().others.size())
							{
								Global.Instance().others.remove(0);
							}
						}
						else
						{
							Global.Instance().others.set(i, dp);
						}
					}
				}
				catch (Exception ex) {}
			}
		}
	};
}
